package com.mall.shopping.services;

//import com.cskaoyan.gateway.bo.ItemInfAll_X;

import com.mall.commons.tool.exception.BizException;
import com.mall.commons.tool.redisconfig.RedissonAutoConfiguration;
import com.mall.shopping.ICartService;
//import com.mall.shopping.bootstrap.otherObject.CartInfX;
import com.mall.shopping.constants.ShoppingRetCode;
import com.mall.shopping.converter.CartItemConverter;
import com.mall.shopping.dal.entitys.Item;
import com.mall.shopping.dal.entitys.ItemCat;
import com.mall.shopping.dal.entitys.trolleyAdd.TrolleyAdd;
import com.mall.shopping.dal.entitys.trolleyAdd.TrolleyAddMapper;
import com.mall.shopping.dal.persistence.ItemCatMapper;
import com.mall.shopping.dal.persistence.ItemMapper;
import com.mall.shopping.dto.*;
import com.mall.shopping.services.cache.CacheManager;
import com.mall.shopping.utils.ExceptionProcessorUtils;
import com.mall.user.constants.SysRetCodeConstants;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Service;
import org.checkerframework.checker.units.qual.A;
import org.checkerframework.checker.units.qual.K;
import org.redisson.Redisson;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import tk.mybatis.mapper.entity.Example;

import java.lang.reflect.Array;
import java.util.*;

/**
 * @author XuBang
 * @TODO:
 * @date 2021/10/31$
 * @trainOfthought:
 */
@Slf4j
@Service
public class ICartServiceImpl implements ICartService {
    //1.注入对应的Mapper：干活的
    @Autowired
    ItemMapper itemMapper;

    //2.注入转化器：数据库格式--->DTO响应格式(com.mall.shopping.converter)
    @Autowired
    CartItemConverter cartItemConverter;

    //TrolleyAdd：添加请求参数到购物车的代理对象
    @Autowired
    TrolleyAddMapper trolleyAddMapper;

//    @Autowired
//    Redisson redisson;

    //直接注入redissonClient,进行使用
    @Autowired
    RedissonClient redissonClient;

    //缓存事务对象
    @Autowired
    CacheManager cacheManager;
    //3.实现接口，重写方法：(api路径下)

    /**
     * 获取购物车商品列表
     *
     * @param request
     * @return
     */
    @Override
    public CartListByIdResponse getCartListById(CartListByIdRequest request) {
        // 给request的userId赋值
        // 从redis中获取userId
        RMap<Object, Object> clientMap = redissonClient.getMap("mapKey-34");
        long userId = Long.parseLong((String) clientMap.get("userId"));
        request.setUserId(userId);

        //4.创建用于封装的response对象
        CartListByIdResponse response = new CartListByIdResponse();

        //5.对request参数校验（标配）、mapper处理参数返回结果A、converter转化A、response进一步封装A、返回
        List<CartProductDto> cartProductDtos = new ArrayList<>();//用于封装返回的购物车商品详细信息(多个商品)
        try {
            request.requestCheck();  //参数校验
            //******************************************上述内容不存在问题，下方需要进一步调整*****************************************


//            //a.根据用户id，获取商品id      根据用户id，在tb_trolley中查询，可以寻找到itemId，就是：商品id     productNum：该商品的添加到购物车中的数量（根据用户id，去tb_trolley中查询）
//            Example example = new Example(TrolleyAdd.class);
//            Example.Criteria criteria = example.createCriteria();
//            criteria.andEqualTo("userId",request.getUserId());
//            List<TrolleyAdd> trolleyAdds = trolleyAddMapper.selectByExample(example);   //默认一个用户id，对应多条数据：多个商品id及数量
//
//            for (TrolleyAdd trolleyAdd : trolleyAdds) {
//                CartProductDto cartProductDto = new CartProductDto();   //封装返回的购物车商品详细信息（单个商品）
//                //b.根据商品id，获取salePrice\limitNum\productName\productImg 从tb_item表格中
//                Item item = itemMapper.selectByPrimaryKey(cartProductDto.getProductId());
//
//                //c.将上述数据及商品id\checked\productNum封装到单个CartProductDto实例中
//                cartProductDto.setChecked("暂时不知道填啥");  //d.    checked：估计是：标记购物车中商品是否被选中*******需要进一步确认*******(添加购物车，可能需要添加该字段；但不确定)
//                cartProductDto.setLimitNum(Long.valueOf(item.getLimitNum()));
//                cartProductDto.setProductId(trolleyAdd.getItemId());
//                cartProductDto.setProductImg(item.getImage());
//                cartProductDto.setProductName(item.getTitle());
//                cartProductDto.setProductNum(Long.valueOf(trolleyAdd.getNum()));
//                cartProductDto.setSalePrice(item.getPrice());
//
//                cartProductDtos.add(cartProductDto);  //封装到列表中
//            }
//            封装上述数据（可能用到converter器）*********************目前没有用到*************

            //根据request中传入的userId,在redis中，获取多个productId
            //根据redissonClient 对应的hash表名，即：自定义的userId，获取多个key：productId ；然后，根据key获取对应的 value：CartProductDto实例对象；
            // 现在遇见的问题：查找不到使用redissonClient，获取所有key的方法
            RMap<Long, CartProductDto> map = redissonClient.getMap(request.getUserId().toString()); //获取userId对应的key-value表
            for (Long productId : map.keySet()) {    //遍历所有的map.keySet，获取单个的productId
                //核心：应该在加入购物车时，就根据userId，获取productId,从数据库中获取对应的：salePrice、limitNum、productName、productimg；从redis中获取productNum、checked ，将这些数据整体作为一个对象，封装到redis中
                //那么此处：直接根据userId,获取多个productId,直接从redis中获取对应的对象，进行封装，响应
                CartProductDto o1 = map.get(productId);  //o1:一个商品对象，包含：productId、salePrice、productNum、limitNum、productName、productImg、checked
                cartProductDtos.add(o1);
            }

//            for (Long productId : mapCache.values()) {   //遍历该userId对应的productId    *********************暂时不确定，mapCache.values遍历是否是：productId
//                //原先：根据productId,从数据库中获取对应的：salePrice、limitNum、productName、productimg；从redis中获取productNum、checked ，将如上数据封装到响应数据中;
//
//                //核心：应该在加入购物车时，就根据userId，获取productId,从数据库中获取对应的：salePrice、limitNum、productName、productimg；从redis中获取productNum、checked ，将这些数据整体作为一个对象，封装到redis中
//                //那么此处：直接根据userId,获取多个productId,直接从redis中获取对应的对象，进行封装，响应
//
//                Long aLong = new Long((String) productId);
//                CartProductDto o1 = map.get(productId);  //o1:一个商品对象，包含：productId、salePrice、productNum、limitNum、productName、productImg、checked
//                cartProductDtos.add(o1);
//            }

            //*****************************************下方内容不存在问题，上方需要进一步调整*********************************************

            response.setCode(ShoppingRetCode.SUCCESS.getCode());
            response.setMsg(ShoppingRetCode.SUCCESS.getMessage());
            response.setCartProductDtos(cartProductDtos);

        } catch (Exception e) {
            e.printStackTrace();
            response.setCode(ShoppingRetCode.SUCCESS.getCode());
            response.setMsg(ShoppingRetCode.SUCCESS.getMessage());
        }
        return response;
    }

    /**
     * 将商品添加到购物车中
     *
     * @param request
     * @return
     */
    @Override
    public AddCartResponse addToCart(AddCartRequest request) {
        System.out.println("service:" + request.getItemId() + request.getNum() + request.getUserId());

        //1.创建用于封装的response对象
        AddCartResponse response = new AddCartResponse();

        //2.对request参数校验（标配）、mapper处理参数返回结果A、converter转化A、response进一步封装A、返回
        try {
            //request参数校验
            request.requestCheck();

//版本一：
//            //mapper干活：将传入的参数，插入：新建的数据库表格中
//            TrolleyAdd trolley = new TrolleyAdd();
//            trolley.setUserId(request.getUserId());
//            trolley.setItemId(request.getItemId());
//            trolley.setNum(request.getNum());
//
//            int insertNum = trolleyAddMapper.insert(trolley);//将数据封装后，插入数据库********如果出现问题：可能是TrolleyAdd和数据库没有完全一致

           /* //使用redisClient进行数据的存储
            RMap<Object, Object> map = redissonClient.getMap("");    //获取hash表名
            map.put("","");  //根据key,放入value
            map.get("");   //根据key，取出value
            map.remove("");
            //根据key存储对象*********操作熟悉一下
            //根据key   update  ：应该是：先删除，再添加*/

            /**
             * 将购物车数据，插入到数据库中，效率太低，资源浪费严重；以下逻辑，使用redis重新规划一下
             */

//版本二：
//           //a.将request中：userId、itemId、num存储到redis中，并添加默认checked：true
//                //以：userId作为hash表名,itemId作为key;num和checked封装为对象，进行存储
//               //a.1数据准备
//            String checked = "true";
////            request
//            CartInfX cartInfX = new CartInfX();
//            cartInfX.setNum(request.getNum());
//            cartInfX.setChecked(checked);
//
//            //a.2数据存储
//            RMap<Object, Object> map = redissonClient.getMap(request.getUserId().toString());  //创建hash表
//            map.put(request.getItemId(),cartInfX);


            //******************************根据“获取购物车列表”发现：最好不止存储下方数据
            //核心：应该在加入购物车时，就根据userId，获取productId,从数据库中获取对应的：
            // salePrice、limitNum、productName、productimg；从redis中获取productNum、checked ，将这些数据整体作为一个对象，封装到redis中
            //那么此处：直接根据userId,获取多个productId,直接从redis中获取对应的对象，进行封装，响应
            //******************************
            //1.从request中获取：userId、itemId、num

            //2.第一部分数据：（从数据库中查询）根据itemId，也就是：productId,从tb_item中，获取：salePrice、limitNum、productName、productimg；
            Item item = itemMapper.selectByPrimaryKey(request.getItemId());   //根据商品id-itemId，获取商品详情

            //3.第二部分数据：request中获取：num，也就是：productNum 和itemId(productId)    &  默认自定义：checked:String checked = "true";
            String checked = "true";

            //4.将2和3中的数据，封装到一个对象ItemInfAll_X中；创建userId对应的hash表，key:productId  value：存储该对象
            CartProductDto list = new CartProductDto();    //原配，如果下方存在问题；可以使用该条
//            ItemInfAll_X list = new ItemInfAll_X();
            list.setProductId(request.getItemId());
            list.setSalePrice(item.getPrice());
            list.setProductNum(request.getNum().longValue());
            list.setLimitNum(item.getLimitNum().longValue());
            list.setChecked(checked);
            list.setProductName(item.getTitle());
//            list.setProductImg(item.getImage());    //多张图片，后续再处理：小问题
            list.setProductImg(item.getImageBig());   //获取大图：第一张图

            //5.将该对象存储到redis中，方便后续使用
            RMap<Object, Object> map = redissonClient.getMap(request.getUserId().toString());   //创建hash表:以userId作为表名
            map.put(request.getItemId(), list);  //以商品id，作为key；list实例作为value；------------->后续“购物车列表查询”，可以直接根据商品id，获取该对象
            //b.测试

            response.setCode(ShoppingRetCode.SUCCESS.getCode());
            response.setMsg(ShoppingRetCode.SUCCESS.getMessage());
            response.setResult("成功");
//            response.setTimestamp(System.currentTimeMillis());   //获取13位毫秒级时间戳   ***********************工具类中已经内置，再考虑一下；这个地方**************
        } catch (Exception e) {
            e.printStackTrace();
            response.setCode(ShoppingRetCode.DB_EXCEPTION.getCode());
            response.setMsg(ShoppingRetCode.DB_EXCEPTION.getMessage());
        }
        return response;
    }

    /**
     * 更新购物车中的商品
     *
     * @param request
     * @return
     */
    @Override
    public UpdateCartNumResponse updateCartNum(UpdateCartNumRequest request) {
        //1.创建用于封装的response对象
        UpdateCartNumResponse response = new UpdateCartNumResponse();

        try {
            //request参数校验
            request.requestCheck();
            //版本一：
            //2.对request参数校验（标配）、mapper处理参数返回结果A、converter转化A、response进一步封装A、返回
            //将request中对应的参数封装到TrolleyBo中（自定义通用mapper进行数据库处理）

            //配置对应的数据库表格和tk_mybatis相关的通用mapper

            //根据userId和checked，指定规则；利用通用mapper修改选中的商品的数量（这是我认为的购物车商品更新，没有其他数据，只能更新数量）

            //类似添加商品，对response进行封装，返回

            /**
             * 重新思考：使用redis，直接存储对象
             */
            //1.从request中获取对应的userId，从redis中获取购物车商品的所有key：itemId
            RMap<Long, Object> map = redissonClient.getMap(request.getUserId().toString());
            for (Long productId : map.keySet()) {
                //2.根据request中的itemId,确定对应的商品信息信息
                if (productId.equals(request.getItemId())) {
                    //3.使用：request中的num和checked，替换：redis中的对应数据
                    CartProductDto goodsDetails = (CartProductDto) map.get(productId);
                    goodsDetails.setChecked(request.getChecked());
                    goodsDetails.setProductNum(request.getNum().longValue());

                    //根据productId，修改checked(先删除，在添加)----
                    map.remove(productId);
                    map.put(productId,goodsDetails);

                    System.out.println(goodsDetails.getChecked());     //测试
                    System.out.println(goodsDetails.getProductNum());
                }
            }
            response.setCode(ShoppingRetCode.SUCCESS.getCode());
            response.setMsg(ShoppingRetCode.SUCCESS.getMessage());
            response.setResult("成功");
        } catch (Exception e) {
            e.printStackTrace();
            response.setCode(ShoppingRetCode.DB_EXCEPTION.getCode());
            response.setMsg(ShoppingRetCode.DB_EXCEPTION.getMessage());
        }
        return response;
    }

    /**
     * auther：yangwenjian
     * todo: 选择购物车中的所有商品
     * @param request
     * @return
     */

    @Override
    public CheckAllItemResponse checkAllCartItem(CheckAllItemRequest request) {
        CheckAllItemResponse response = new CheckAllItemResponse();
        try {
            request.requestCheck();
            Map<Long, CartProductDto> userCarts = getUserCarts(request.getUserId());
            Collection<CartProductDto> values = userCarts.values();
            //全部选中
            for (CartProductDto value : values) {
                value.setChecked(request.getChecked());
                userCarts.put(value.getProductId(),value);
            }
            //更新购物车
            updateCarts(userCarts,request.getUserId());
            response.setCode(ShoppingRetCode.SUCCESS.getCode());
            response.setMsg(ShoppingRetCode.SUCCESS.getMessage());

        }catch (Exception e){
            e.printStackTrace();
            response.setCode(ShoppingRetCode.SYSTEM_ERROR.getCode());
            response.setMsg(ShoppingRetCode.SYSTEM_ERROR.getMessage());
        }
        return response;
    }

    /**
     * auther: yangwenjian
     * todo: 更新购物车
     */
    public void updateCarts(Map<Long,CartProductDto> userCarts,Long userId){
        Map<Long, Map<Long, CartProductDto>> carts = cacheManager.getCarts();
        carts.put(userId,userCarts);
    }

    /**
     * auther: yangwenjian
     * todo: 获取当前用户购物车
     */
    public Map<Long,CartProductDto> getUserCarts(Long userId){

        //购物车map
        Map<Long, Map<Long, CartProductDto>> carts = cacheManager.getCarts();
        //根据用户id获取当前用户购物车map
        Map<Long, CartProductDto> map = carts.get(userId);
        if (map == null){
             map = new HashMap<>();
        }
        return map;
    }

    /**
     * auther：yangwenjian
     * todo: 删除购物车中的商品
     * @param request
     * @return
     */
    @Override
    public DeleteCartItemResponse deleteCartItem(DeleteCartItemRequest request) {
        DeleteCartItemResponse response = new DeleteCartItemResponse();
            //如果UserId 不为空 进行校验 ，通过商品id删除
            try {
                request.requestCheck();

                deleteCart(request);

                response.setCode(ShoppingRetCode.SUCCESS.getCode());
                response.setMsg(ShoppingRetCode.SUCCESS.getMessage());

            } catch (Exception e) {
                e.printStackTrace();
                response.setCode(ShoppingRetCode.SYSTEM_ERROR.getCode());
                response.setMsg(ShoppingRetCode.SYSTEM_ERROR.getMessage());
            }

        return response;
    }

    /**
     * auther: yangwenjian
     * todo: 删除选中的商品
     * @param request
     * @return
     */
    @Override
    public DeleteCheckedItemResposne deleteCheckedItem(DeleteCheckedItemRequest request) {
        DeleteCheckedItemResposne resposne = new DeleteCheckedItemResposne();
        try {
            //参数校验
            request.requestCheck();
            //根据用户id获取购物车数据
            RMap<String, CartProductDto> map = redissonClient.getMap(request.getUserId().toString());
            //遍历values，找到checked为true的商品并删除
            for (CartProductDto value : map.values()) {
                if ("true".equals(value.getChecked())) {
                    //获取商品id，删除该id对应的商品
                    Long productId = value.getProductId();
                    map.remove(productId);

                }
            }
            resposne.setCode(ShoppingRetCode.SUCCESS.getCode());
            resposne.setMsg(ShoppingRetCode.SUCCESS.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            resposne.setCode(ShoppingRetCode.DB_EXCEPTION.getCode());
            resposne.setMsg(ShoppingRetCode.DB_EXCEPTION.getMessage());
        }
        return resposne;
    }

    /**
     * auther：yangwenjian
     * todo：抽取删除方法
     * @param request
     */
    private void deleteCart(DeleteCartItemRequest request) {
        Map<Long, CartProductDto> userCarts = getUserCarts(request.getUserId());

        RMap<Object, Object> map = redissonClient.getMap(request.getUserId().toString());
        map.remove(request.getItemId());
        //删除购物车中商品
        userCarts.remove(request.getItemId());
        RScoredSortedSet<Long> userAddCartTime = cacheManager.getUserAddCartTime(request.getUserId());
        //删除商品排序信息
        map.remove(request.getItemId());
        updateCarts(userCarts,request.getUserId());
    }

    @Override
    public ClearCartItemResponse clearCartItemByUserID(ClearCartItemRequest request) {

        ClearCartItemResponse response = new ClearCartItemResponse();

        try {
            request.requestCheck();

            RMap<Object, Object> map = redissonClient.getMap(request.getUserId().toString());

            List<Long> productIds = request.getProductIds();

            if (productIds == null) {
                response.setCode(ShoppingRetCode.REQUISITE_PARAMETER_NOT_EXIST.getCode());
                response.setMsg(ShoppingRetCode.REQUISITE_PARAMETER_NOT_EXIST.getMessage());
                return response;
            }

            for (Long productId : productIds) {
                map.remove(productId);
            }

            response.setCode(ShoppingRetCode.SUCCESS.getCode());
            response.setMsg(ShoppingRetCode.SUCCESS.getMessage());
        } catch (Exception e) {
            log.error("ICartServiceImpl.clearCartItemByUserID Occur Exception :" + e);
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
        }
        return response;
    }
}
